#include "json_rpc_client.hpp"
#include <stdexcept>

JsonRpcClient::JsonRpcClient (const std::string &connect_addr) :
    context_ (zmq_ctx_new ()), next_id_ (1)
{
    socket_ = zmq_socket (context_, ZMQ_DEALER);

    // 设置客户端身份
    std::string identity = "client_" + std::to_string (rand ());
    zmq_setsockopt (socket_, ZMQ_IDENTITY, identity.c_str (), identity.size ());

    if (zmq_connect (socket_, connect_addr.c_str ()) != 0) {
        throw std::runtime_error ("Failed to connect");
    }
}

JsonRpcClient &JsonRpcClient::getInstance (const std::string &connect_addr)
{
    static JsonRpcClient instance (connect_addr);
    return instance;
}

JsonRpcClient::~JsonRpcClient ()
{
    zmq_close (socket_);
    zmq_ctx_destroy (context_);
}

json JsonRpcClient::call (const std::string &method, const json &params)
{
    json request = {{"jsonrpc", "2.0"},
                    {"method", method},
                    {"params", params},
                    {"id", next_id_++}};

    std::string request_str = request.dump ();

    // 发送请求
    zmq_msg_t msg;
    zmq_msg_init_size (&msg, request_str.size ());
    memcpy (zmq_msg_data (&msg), request_str.data (), request_str.size ());
    zmq_msg_send (&msg, socket_, 0);
    zmq_msg_close (&msg);

    // 接收响应
    zmq_msg_t reply;
    zmq_msg_init (&reply);
    zmq_msg_recv (&reply, socket_, 0);

    std::string response_str (static_cast<char *> (zmq_msg_data (&reply)),
                              zmq_msg_size (&reply));
    zmq_msg_close (&reply);

    json response = json::parse (response_str);

    if (response.contains ("error")) {
        throw std::runtime_error (response["error"]["message"]);
    }

    return response["result"];
}